package sunbao.ido.util;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * @Classname DateUtils
 * @Description
 * @Date 2019/12/12 16:09
 * @Created by Administrator
 */
public class DateUtils {
    private static final Logger logger = LoggerFactory.getLogger(DateUtils.class);

    private static DateFormat dateFormat;

    public static final String SECOND = "SECOND";
    public static final String MIN = "MIN";
    public static final String HOUR = "HOUR";
    public static final String DAY = "DAY";
    public static final String WEEK = "WEEK";
    public static final String MONTH = "MONTH";

    /**
     * yyyy-MM-dd HH:mm:ss
     */
    public static final String pattern_default = "yyyy-MM-dd HH:mm:ss";
    public static final String pattern_yyyy_MM = "yyyy-MM";
    public static final String pattern_yyyy_MM_dd = "yyyy-MM-dd";
    public static final String pattern_yyyyMMdd = "yyyyMMdd";
    public static final String pattern_yyyyMM = "yyyyMM";
    public static final String pattern_yyyyMMddHHmmss = "yyyyMMddHHmmss";
    public static final String pattern_yyyyMMddHHmmssSSS = "yyyyMMddHHmmssSSS";
    public static final String pattern_HH_mm_ss = "HH:mm:ss";
    public static final String pattern_ISODate = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
    public static final int dayTimeMillis = 24 * 60 * 60 * 1000;
    public static final Long eight_H = 28800000L;

    public static Date string2Date(String date) {
        return string2Date(date, null);
    }

    public static Date string2Date(String date, String pattern) {
        if (date == null || "".equals(date.trim()))
            return null;
        try {
            return getDateFormat(pattern).parse(date);
        } catch (Exception e) {
            logger.error("020058E0001:{},{}", "时间转换异常", e);
            return null;
        }
    }

    public static String date2String(Date d) {
        return date2String(d, null);
    }

    public static String date2String(Date d, String pattern) {

        if (d == null)
            return "";
        return getDateFormat(pattern).format(d);

    }

    public static DateFormat getDateFormat(String pattern) {
        if (pattern == null || "".equals(pattern.trim())) {
            pattern = pattern_default;
        }
        dateFormat = new SimpleDateFormat(pattern);
        return dateFormat;
    }

    public static Date now() {
        return new Date();
    }

    /**
     * yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String nowString() {
        return nowString(pattern_default);
    }

    public static String nowString(String pattern) {
        return getDateFormat(pattern).format(now());
    }


    public static Date dayBegin(Calendar c) {
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }


    /**
     * 获取当日开始时间, yyyy-MM-dd 00:00:00
     *
     * @param date
     * @return
     */
    public static Date dayBegin(Date date) {
        Calendar c = getCalendar(date);
        return dayBegin(c);
    }

    public static Date dayBegin() {
        return dayBegin(new Date());
    }

    public static Date dayEnd(Calendar c) {
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 999);
        return c.getTime();
    }

    /**
     * 获取当日截止时间, yyyy-MM-dd 23:59:59
     *
     * @param date
     * @return
     */
    public static Date dayEnd(Date date) {
        Calendar c = getCalendar(date);
        return dayEnd(c);
    }

    public static Date dayEnd() {
        return dayEnd(new Date());
    }

    /**
     * 获取本月第一天
     *
     * @param date
     * @return
     */
    public static Date monthBegin(Date date) {
        Calendar c = getCalendar(date);
        c.set(Calendar.DAY_OF_MONTH, 1);
        return dayBegin(c);
    }

    public static Date monthBegin() {
        return monthBegin(new Date());
    }

    /**
     * 获取本月最后的时间
     *
     * @param date
     * @return
     */
    public static Date monthEnd(Date date) {
        Calendar c = getCalendar(date);
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
        return dayEnd(c);
    }

    public static Date monthEnd() {
        return monthEnd(new Date());
    }

    /**
     * 获取本月第一天
     *
     * @param date
     * @return
     */
    public static Date yearBegin(Date date) {
        Calendar c = getCalendar(date);
        c.set(Calendar.MONTH, Calendar.JANUARY);
        c.set(Calendar.DAY_OF_MONTH, 1);
        return dayBegin(c);
    }

    public static Date yearBegin() {
        return yearBegin(new Date());
    }

    /**
     * 获取本月最后的时间
     *
     * @param date
     * @return
     */
    public static Date yearEnd(Date date) {
        Calendar c = getCalendar(date);
        c.set(Calendar.MONTH, Calendar.DECEMBER);
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
        return dayEnd(c);
    }

    public static Date yearEnd() {
        return yearEnd(new Date());
    }

    /**
     * 获取本月最后一天
     *
     * @param date
     * @return
     */
    public static Date lastDayOfMonth(Date date) {
        Calendar c = getCalendar(date);
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
        return dayBegin(c);
    }

    /**
     * 获取指定时间的那天 23:59:59.999 的时间
     *
     * @param
     * @return
     */
    public static Calendar getCalendar(int year, int month, int day) {

        if (month < 0 || month > 11) {
            throw new RuntimeException("invalid month value 0~11");
        }
        if (day < 1 || day > 31) {
            throw new RuntimeException("invalid date value 1~31");
        }
        Calendar now = Calendar.getInstance();
        now.setTime(dayBegin(new Date()));
        now.set(year, Calendar.JANUARY, day);
        now.add(Calendar.MONTH, month);
        return now;
    }

    public static Calendar getCalendar(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal;
    }

    public static String getDateString(int year, int month, int day) {
        return date2String(getDate(year, month, day), pattern_yyyy_MM_dd);
    }

    public static String getDateString(Date date) {
        return date2String(date, pattern_yyyy_MM_dd);
    }

    public static String getDateString() {
        return date2String(now(), pattern_yyyy_MM_dd);
    }

    public static Date getDate(int year, int month, int day) {
        return getCalendar(year, month, day).getTime();
    }

    public static String getDateString_yyyyMM(int year, int month) {
        return date2String(getDate(year, month, 1), pattern_yyyyMM);
    }


    public static String getNextNDate(String time, int n) {
        try {
            Calendar cal = Calendar.getInstance();
            String year = time.substring(0, 4);
            String month = time.substring(5, 7);
            String date = time.substring(8, 10);
            cal.set(Calendar.YEAR, Integer.parseInt(year));
            cal.set(Calendar.MONTH, Integer.parseInt(month) - 1);
            cal.set(Calendar.DATE, Integer.parseInt(date));
            cal.add(Calendar.DATE, n);
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            return df.format(cal.getTime());

        } catch (Exception e) {
            logger.error("020058E0001:{},{}", "进行日期运算时输入得参数不符合系统规格", e);

            throw new RuntimeException("进行日期运算时输入得参数不符合系统规格." + e);

        }
    }

    /**
     * 获取某个日期的前n个月
     *
     * @param date
     * @return
     */
    public static Date getPreNMonthDate(Date date, int n) {
        if (date == null || n <= 0) {
            return now();
        }
//        int month = getCalendar(date).get(Calendar.MONTH);
//        int year = (n-month+12)/12;
//        month = (month - n)%12 + 12*(year>0?1:0) - 1;
        Calendar cal = getCalendar(date);
        cal.add(Calendar.MONTH, -n);
        return cal.getTime();
    }

    public static Date getPreMonthDate(Date date) {
        return getPreNMonthDate(date, 1);
    }

    public static Date getPreMonthDate() {
        return getPreMonthDate(now());
    }

    /**
     * 获取某个日期的前n个月
     *
     * @param date
     * @return
     */
    public static Date getNextNMonthDate(Date date, int n) {
        if (date == null || n <= 0) {
            return now();
        }
//        int month = getCalendar(date).get(Calendar.MONTH);
//        int year = (n-month+12)/12;
//        month = (month - n)%12 + 12*(year>0?1:0) - 1;
        Calendar cal = getCalendar(date);
        cal.add(Calendar.MONTH, n);
        return cal.getTime();
    }

    public static Date getNextMonthDate(Date date) {
        return getNextNMonthDate(date, 1);
    }

    public static Date getNextMonthDate() {
        return getNextMonthDate(now());
    }


    /**
     * 获取某个时间整点
     *
     * @param date
     * @return
     */
    public static Date hourBegin(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 得到上N个小时整点
     *
     * @param date
     * @return
     */
    public static Date getPreHourBegin(Date date) {
        return getPreNHour(hourBegin(date), 1);
    }

    /**
     * 得到上N个小时整点
     *
     * @param date
     * @return
     */
    public static Date getPreNHourBegin(Date date, int n) {
        return getPreNHour(hourBegin(date), n);
    }

    /**
     * 得到上个小时时间
     *
     * @param date
     * @param n
     * @return
     */
    public static Date getPreNHour(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, (0 - n));
        return calendar.getTime();
    }


    public static Date getPreNDate(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, (0 - n));
        return dayBegin(calendar.getTime());
    }

    public static Date getPreDate(Date date) {
        return getPreNDate(date, 1);
    }

    public static Date getNextNDate(Date date, int n) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, n);
        return dayBegin(calendar.getTime());
    }

    public static Date getNextDate(Date date) {
        return getNextNDate(date, 1);
    }

    public static Long daysBetween(Date date1, Date date2) {
        return Math.abs((dayBegin(date1).getTime() - dayBegin(date2).getTime()) / dayTimeMillis);
    }

    /**
     * 获取昨天的日期
     *
     * @return
     */
    public static Date getYestDate() {
        return getPreNDate(new Date(), 1);
    }

    /**
     * 当前日期是否是今日
     *
     * @param curDate
     * @return
     */
    public static boolean isToday(Date curDate) {
        return isDay(new Date(), curDate);
    }

    /**
     * 判断两个日期是否是同一日
     *
     * @param date
     * @param curDate
     * @return
     */
    public static boolean isDay(Date date, Date curDate) {
        if (dayBegin(date).compareTo(dayBegin(curDate)) == 0) {
            return true;
        }
        return false;
    }

    /**
     * 是否为昨日
     *
     * @param curDate
     * @return
     */
    public static boolean isYestDay(Date curDate) {
        return isDay(getYestDate(), curDate);
    }

    public static String charAddDate(String date, String ch) {

        if (StringUtils.isNotEmpty(date)) {
            if (date.length() == 8) {
                return date.substring(0, 4) + ch + date.substring(4, 6) + ch + date.substring(6);
            }
            if (date.length() == 10) {
                return date.substring(0, 4) + ch + date.substring(5, 7) + ch + date.substring(8);
            }
        }
        return date;
    }

    /**
     * 当前时间戳的月份天数
     *
     * @param timeMillis 时间戳
     * @return 天数
     */
    public static int getMonthLastDay(String timeMillis) {
        try {
            Date date = new Date(Long.valueOf(timeMillis));
            Calendar a = Calendar.getInstance();
            a.setTime(date);
            //把日期设置为当月第一天
            a.set(Calendar.DATE, 1);
            //日期回滚一天，也就是最后一天
            a.roll(Calendar.DATE, -1);
            return a.get(Calendar.DATE);
        } catch (Exception e) {
            logger.error("error, ", e);
            return 0;
        }
    }

    /**
     * 当前时间度量下的毫秒数
     *
     * @param metric     时间度量单位
     * @param timeMillis 当前时间戳
     * @return
     */
    public static long metricMills(int metric, String timeMillis) {
        // 秒
        if (metric == Calendar.SECOND) {
            return 1000;
        }
        // 分钟
        else if (metric == Calendar.MINUTE) {
            return 1000 * 60L;
        }
        // 小时
        else if (metric == Calendar.HOUR) {
            return 1000 * 60 * 60L;
        }
        // 天
        else if (metric == Calendar.DATE) {
            return 1000 * 60 * 60 * 24L;
        }
        // 月
        else if (metric == Calendar.MONTH) {
            return (1000 * 60 * 60 * 24L * getMonthLastDay(timeMillis));
        } else {
            return 0;
        }
    }

    public static String timeStamp(int metric, String timeMillis) {
        try {
            String format = "yyyyMMddHHmmss";
            // 秒
            if (metric == Calendar.SECOND) {
                format = "yyyyMMddHHmmss";
            }
            // 分钟
            else if (metric == Calendar.MINUTE) {
                format = "yyyyMMddHHmm";
            }
            // 小时
            else if (metric == Calendar.HOUR) {
                format = "yyyyMMddHH";
            }
            // 天
            else if (metric == Calendar.DATE) {
                format = "yyyyMMdd";
            }
            // 月
            else if (metric == Calendar.MONTH) {
                format = "yyyyMM";
            }
            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
            long lt = new Long(timeMillis);
            Date date = dateFormat.parse(dateFormat.format(new Date(lt)));
            long ts = date.getTime();
            return String.valueOf(ts);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 获取两个日期相差的月数
     */
    public static int getMonthBetween(Date start, Date end) {
        if (start.after(end)) {
            Date t = start;
            start = end;
            end = t;
        }
        Calendar startCalendar = Calendar.getInstance();
        startCalendar.setTime(start);
        Calendar endCalendar = Calendar.getInstance();
        endCalendar.setTime(end);
        Calendar temp = Calendar.getInstance();
        temp.setTime(end);
        temp.add(Calendar.DATE, 1);

        int year = endCalendar.get(Calendar.YEAR)
                - startCalendar.get(Calendar.YEAR);
        int month = endCalendar.get(Calendar.MONTH)
                - startCalendar.get(Calendar.MONTH);

        if ((startCalendar.get(Calendar.DATE) == 1)
                && (temp.get(Calendar.DATE) == 1)) {
            return year * 12 + month + 1;
        } else if ((startCalendar.get(Calendar.DATE) != 1)
                && (temp.get(Calendar.DATE) == 1)) {
            return year * 12 + month;
        } else if ((startCalendar.get(Calendar.DATE) == 1)
                && (temp.get(Calendar.DATE) != 1)) {
            return year * 12 + month;
        } else {
            return (year * 12 + month - 1) < 0 ? 0 : (year * 12 + month);
        }
    }

    /**
     * 计算两个日期相差间隔天数
     *
     * @param start
     * @param end
     * @return
     */
    public static int betweenDays(Date start, Date end) {

        if (start == null || end == null) {
            throw new IllegalArgumentException("date is null, check it again");
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(start);
        long time1 = cal.getTimeInMillis();
        cal.setTime(end);
        long time2 = cal.getTimeInMillis();
        long between_days = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(between_days));
    }

    public static void main(String[] args) {
        System.out.println(date2String(getPreNMonthDate(string2Date("2016-03-30", pattern_yyyy_MM_dd), 1)));
        System.out.println(date2String(getCalendar(now()).getTime()));
    }


}
